home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / vbcc / machines / amigappc / libsrc / fd2libPPC.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-24  |  16.9 KB  |  643 lines

  1. /*  fd2lib  by Volker Barthelmann                         */
  2. /*  rework 09/96 by Johnny Teveßen <j.tevessen@line.org>  */
  3. /*  PPC version by Volker Barthelmann in 12/97            */
  4.  
  5. /*  "T:"s removed: Not very portable!
  6. */
  7.  
  8. #define NDEBUG
  9.  
  10. #ifdef _DCC
  11. #  define CTYPE_NEAR
  12. #endif
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <stdarg.h>
  19.  
  20. const char VersTag[] = "\0$VER: fd2libPPC 0.1 (21.12.1997)";  /* AmigaOS version string. Doesn't hurt... */
  21.  
  22. #define MAXLINELEN       1000
  23. #define BUFFEREDLEN     16384   /* 1024 is standard */
  24.  
  25. #define NUMREGS        16
  26.  
  27. static const char *regnames[NUMREGS] =
  28. {
  29.   "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
  30.   "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"
  31. };
  32.  
  33. enum
  34. {
  35.   A0=0, A1, A2, A3, A4, A5, A6, A7,
  36.   D0  , D1, D2, D3, D4, D5, D6, D7
  37. };
  38.  
  39. #define SMALLCODE        1  /* not available for PPC */
  40. #define SMALLDATA        2
  41. #define FASTCALL         4  /* not available for PPC */
  42. #define NEWNOTATE        8  /* not available for PPC */
  43. #define VARGSLOGIC      16
  44. #define DEBUG           32
  45.  
  46. #ifndef   TRUE
  47.    typedef short BOOL;
  48. #  define TRUE  1
  49. #  define FALSE 0
  50. #endif
  51.  
  52. #ifndef   NULL
  53. #  define NULL ((void *)0L)
  54. #endif
  55.  
  56. #ifdef __GNUC__
  57. #  define gnuspec(x) x
  58. #else
  59. #  define gnuspec(x)
  60. #endif
  61.  
  62. #define NORETURN gnuspec(__attribute__ ((noreturn)))
  63.  
  64. static const char *varargs[] =
  65. {
  66. #include "vargs.h"
  67.   NULL, NULL
  68. };
  69.  
  70. static void ExitFailure(const char *, const char *) NORETURN;
  71.  
  72. static void
  73. ExitFailure(const char *cause, const char *insertme)
  74. {
  75.   fprintf(stderr, cause, insertme);
  76.  
  77.   exit(EXIT_FAILURE);
  78. }
  79.  
  80. static void
  81. check(const char *ptr)
  82. {
  83.   if(!*ptr)
  84.   {
  85.     ExitFailure("Unexpected EOL\n", NULL);
  86.   }
  87. }
  88.  
  89. static void warnhim(int linenr, const char *format, ...) gnuspec(__attribute__ ((format (printf, 2, 3))));
  90.  
  91. static void
  92. warnhim(int linenr, const char *format, ...)
  93. {
  94.   char linebuf[250];
  95.   va_list vl;
  96.  
  97.   va_start(vl,format);
  98.   vsprintf(linebuf, format, vl);
  99.   va_end(vl);
  100.  
  101.   fprintf(stderr, "Warning line %d: %s\n", linenr, linebuf);
  102. }
  103.  
  104. static FILE *
  105. OpenLVO(const char *name, const char *outdir, const char *outform)
  106. {
  107.   FILE *lvos;
  108.   char lvoname[MAXLINELEN];
  109.  
  110.   strcpy(lvoname, outdir);
  111.  
  112.   if(name)
  113.   {
  114.     char *k = (char *)name, *p;
  115.     int lvonamlen;
  116.  
  117.     if((p = strrchr(k, '/')) != NULL) k = p + 1;
  118.     if((p = strrchr(k, ':')) != NULL) k = p + 1;
  119.  
  120.     strcat(lvoname, k);
  121.  
  122.     lvonamlen = strlen(lvoname);
  123.  
  124.     if((lvonamlen > 7) && !strcmp(lvoname+lvonamlen-7, "_lib.fd"))
  125.     {
  126.       lvoname[lvonamlen-7] = '\0';
  127.     }
  128.     else if((lvonamlen > 3) && !strcmp(lvoname+lvonamlen-3, ".fd"))
  129.     {
  130.       lvoname[lvonamlen-3] = '\0';
  131.     }
  132.  
  133.     strcat(lvoname, "_lvo.s");
  134.   }
  135.   else
  136.   {
  137.     strcat(lvoname, "fd_lvo.s");
  138.   }
  139.  
  140.   printf(outform, lvoname, lvoname, lvoname);
  141.  
  142.   lvos = fopen(lvoname, "w");
  143.  
  144.   return(lvos);
  145. }
  146.  
  147. static void
  148. ProcessFD(const char *name, int mode, const char *outdir, const char *outform)
  149. {
  150.     FILE *fd, *lvos;
  151.     FILE *out;
  152.     int offset = 0, i, j, count, savecount;
  153.     char function[80], tmpfuncnam[80], ff[MAXLINELEN+8], base[50];
  154.     char line[MAXLINELEN];
  155.     register char *p;
  156.     char *functionp;
  157.     int reg[NUMREGS], loops, linenr = 0;
  158.     BOOL public = -1;           /* Why FALSE? */
  159.  
  160.     /*  "-1" is the initial value for "public". It means:
  161.     **  no statement yet.
  162.     */
  163.  
  164.     *function = *base = *line = '\0';
  165.  
  166.     if(name) fd = fopen(name, "r");
  167.     else     fd = stdin;
  168.  
  169.     if(!fd) ExitFailure("Could not open `%s'\n", name);
  170.  
  171.     setvbuf(fd, NULL, _IOFBF, BUFFEREDLEN);             /* maybe _IOLBF? */
  172.  
  173.     if(!(lvos = OpenLVO(name, outdir, outform)))
  174.       ExitFailure("Could not create lvo file\n", NULL);
  175.  
  176.     setvbuf(lvos, NULL, _IOFBF, BUFFEREDLEN);
  177.  
  178.     for(;;)
  179.     {
  180.         char *k;
  181.  
  182.         if(!fgets(line, MAXLINELEN-1, fd)) ExitFailure("Unexpected EOF\n", NULL);
  183.  
  184.         linenr ++;
  185.  
  186.         if((*line == '*') || !*line) continue;
  187.  
  188.         switch(*line + line[2])
  189.         {
  190.           case ('#'+'b'):
  191.             if(!strncmp(line, "##base", 6))
  192.             {
  193.                 if(*base) warnhim(linenr, "##base detected more than once!");
  194.  
  195.                 p = line+6; while(isspace(*p)) p++;
  196.                 k = base  ; while(isgraph(*p)) *k++ = *p++;
  197.  
  198.                 *k = '\0';
  199.  
  200.                 if(mode & DEBUG) printf("Base set to `%s'\n", base);
  201.                 continue;
  202.             }
  203.  
  204.             if(!strncmp(line, "##bias", 6))
  205.             {
  206.                 p = line+6; while(isspace(*p)) p++;
  207.                 sscanf(p, "%i", &offset);
  208.  
  209.                 if(mode & DEBUG) printf("Bias set to -%d\n", offset);
  210.                 continue;
  211.             }
  212.             break;
  213.  
  214.           case ('#'+'p'):
  215.             if(!strncmp(line, "##public", 8))
  216.             {
  217.                 if(public == TRUE)  warnhim(linenr, "##public after ##public detected!");
  218.                 else                public = TRUE;
  219.  
  220.                 if(mode & DEBUG) printf("Turned on public mode at bias -%d\n", offset);
  221.                 continue;
  222.             }
  223.  
  224.             if(!strncmp(line, "##private", 9))
  225.             {
  226.                 if(public == FALSE) warnhim(linenr, "##private after ##private detected!");
  227.                 else                public = FALSE;
  228.  
  229.                 if(mode & DEBUG) printf("Turned off public mode at bias -%d\n", offset);
  230.                 continue;
  231.             }
  232.             break;
  233.  
  234.           case ('#'+'e'):
  235.             if(!strncmp(line, "##end", 5)) return;
  236.             break;
  237.         }
  238.  
  239.         if(*line == '#')
  240.         {
  241.           warnhim(linenr, "Unknown directive: `%s'!", line);
  242.           continue;
  243.         }
  244.  
  245.         if(!public)
  246.         {
  247.           offset += 6;
  248.           continue;
  249.         }
  250.  
  251.         if(public == -1)
  252.         {
  253.           warnhim(linenr, "Neither ##public nor ##private specified yet. Assuming ##public.");
  254.           public = TRUE;
  255.         }
  256.  
  257.         functionp = function;
  258.  
  259.         for(loops=0; loops<=1; loops++)
  260.         {
  261.             char *p = line; char *k = functionp;
  262.  
  263.             while(isspace(*p)) p++;
  264.  
  265.             if(!loops)
  266.             {
  267.                 while((*p != '(') && *p) *k++ = *p++;
  268.  
  269.                 check(p);
  270.                 *k = '\0';
  271.  
  272.                 fprintf(lvos, "\t.set\tLVO%s,-%d\n"
  273.                               "\t.global\tLVO%s\n",
  274.                               functionp, offset, functionp
  275.                        );
  276.             }
  277.             else
  278.             {
  279.                 while((*p != '(') && *p) p++;
  280.                 check(p);
  281.             }
  282.  
  283.             if(mode & DEBUG) printf("function=%s, loops=%d\n", functionp, loops);
  284.  
  285.             /* Open function stub source file */
  286.  
  287.             sprintf(ff, "%s%s.s", outdir, functionp);
  288.  
  289.             printf(outform, ff, ff, ff);
  290.  
  291.             out = fopen(ff, "w");
  292.             if(!out) ExitFailure("Could not create <%s>\n", functionp);
  293.             setvbuf(out, NULL, _IOFBF, BUFFEREDLEN);
  294.  
  295.             /* Write assembler headers */
  296.  
  297.             fprintf(out,"\t.text\n");
  298.             if(*base) fprintf(out, "\t.global\t%s\n", base+1);
  299.             fprintf(out,"\t.global\tPPCCallOS\n");
  300.             fprintf(out,"\t.global\t%s\n",functionp);
  301.  
  302.             /* Set all registers to 'unused' */
  303.  
  304.             for(i=0; i<NUMREGS; i++) reg[i] = 0;
  305.  
  306.             /* Skip argument names */
  307.  
  308.             while((*p!=')') && *p) p++;
  309.  
  310.             check(p);
  311.             p++;
  312.  
  313.             /* Search for beginning of register list */
  314.  
  315.             while((*p!='(') && *p) p++;
  316.  
  317.             check(p);
  318.             p++;
  319.  
  320.             /* Scan register list */
  321.  
  322.             count = savecount = 0;
  323.  
  324.             while((*p!=')') && *p)
  325.             {
  326.                 /* Check whether register description is valid */
  327.  
  328.                 if((!((*p=='a') || (*p=='A') || (*p=='d') || (*p=='D'))) || !((p[1]>='0') && (p[1]<='7')))
  329.                     ExitFailure("Bad register description\n", NULL);
  330.  
  331.                 /* Convert description to internal enum format */
  332.                 /* Corrected: 'A' was not recognized           */
  333.  
  334.                 if((*p=='a') || (*p=='A')) j = p[1] -  '0';
  335.                 else                       j = p[1] - ('0'-8);
  336.  
  337.                 /* Mark register as used and save its argument counter */
  338.  
  339.                 reg[j] = ++count;
  340.  
  341.                 /* Increase counter if register has to be saved */
  342.  
  343.                 if(!(j==A0 || j==A1 || j==A6 || j==D0 || j==D1))
  344.                   savecount ++;
  345.  
  346.                 /* Search for next register */
  347.  
  348.                 p += 2;
  349.                 while(isspace(*p) && *p)     p++;
  350.  
  351.                 if((*p == '/') || (*p==',')) p++;
  352.                 else if(*p != ')') ExitFailure("Parse error - ')' expected\n", NULL);
  353.  
  354.                 while(isspace(*p) && *p)     p++;
  355.  
  356.                 check(p);
  357.             }
  358.  
  359.             fprintf(out,"\t.align\t3\n%s:\n",functionp);
  360.             if(!loops){
  361.                 fprintf(out,"\tstwu\t1,-96(1)\n\tmflr\t11\n\tstw\t11,100(1)\n");
  362.             }else{
  363.                 int i;
  364.                 /* Hack the stack-frame for varargs. */
  365.                 /* Build stack-frame, but save LR in our own stack-frame, */
  366.                 /* because we have to overwrite the lower 8 bytes of the  */
  367.                 /* caller's frame. */
  368.                 fprintf(out,"\tstwu\t1,-128(1)\n\tmflr\t11\n\tstw\t11,100(1)\n");
  369.                 /* Save the caller's saved SP in our own stack-frame.     */
  370.                 fprintf(out,"\tlwz\t11,128(1)\n\tstw\t11,96(1)\n");
  371.                 /* Store r3-r8 at the top of our stack-frame and r9-r10   */
  372.                 /* at the low 8 bytes of the caller's frame. This way all */
  373.                 /* arguments will reside in one continuous area.          */
  374.                 for(i=3+count-1;i<=10;i++)
  375.                     fprintf(out,"\tstw\t%d,%d(1)\n",i,104+4*(i-3));
  376.             }
  377.             for(i=0; i<NUMREGS; i++) /* Registers */
  378.             {
  379.                 if(reg[i])
  380.                 {
  381.                     if(!loops||reg[i]<count){
  382.                         if(reg[i]<=8)
  383.                             fprintf(out,"\tstw\t%d,",reg[i]+2);
  384.                         else
  385.                             fprintf(out,"\tlwz\t11,%d(1)\n\tstw\t11,",reg[i]*4+4-8*4);
  386.                     }else{
  387.                         fprintf(out,"\taddi\t11,1,%d\n\tstw\t11,",100+count*4);
  388.                     }
  389.  
  390.                     if(i<=7)
  391.                         fprintf(out,"%d(1)\n",68+4*i);
  392.                     else
  393.                         fprintf(out,"%d(1)\n",36+4*(i-8));
  394.  
  395.  
  396.                 }
  397.             } /* for i */
  398.  
  399.             /* Now place the real function call */
  400.  
  401.             fprintf(out,"\tli\t11,-%d\n\tstw\t11,8(1)\n",offset);
  402.             fprintf(out,"\tli\t11,1\n\tstw\t11,12(1)\n\tstw\t11,24(1)\n");
  403.             fprintf(out,"\tlis\t11,%s@ha\n\tlwz\t11,%s@l(11)\n\tstw\t11,92(1)\n",base+1,base+1);
  404.             fprintf(out,"\taddi\t3,1,8\n\tbl\tPPCCallOS\n");
  405.             if(!loops){
  406.                 fprintf(out,"\tlwz\t11,100(1)\n\tmtlr\t11\n");
  407.                 fprintf(out,"\taddi\t1,1,96\n\tblr\n");
  408.             }else{
  409.                 /* Varargs. Rebuild the caller's stack-frame. */
  410.                 fprintf(out,"\tlwz\t11,96(1)\n\tstw\t11,128(1)\n");
  411.                 fprintf(out,"\tlwz\t11,100(1)\n\tmtlr\t11\n");
  412.                 fprintf(out,"\taddi\t1,1,128\n\tblr\n");
  413.             }
  414.             fclose(out);
  415.  
  416.             if(loops != 0) break;
  417.  
  418.             p = (char *) *varargs;
  419.             loops = 3;
  420.  
  421.             if(mode & DEBUG) printf("Searching function `%s' in vargs table...\n", functionp);
  422.  
  423.             if(p != NULL)
  424.             {
  425.               if(mode & VARGSLOGIC)
  426.               {
  427.                 int fnlen = strlen(functionp);
  428.  
  429.                 if((fnlen > 7) && (!strcmp(functionp + fnlen - 7, "TagList")))
  430.                 {
  431.                   /*  xxxTagList function found. Make xxxTags of it
  432.                   */
  433.  
  434.                   strncpy(tmpfuncnam, functionp, fnlen - 4);
  435.                   strcpy (tmpfuncnam + fnlen - 4,    "s"  );
  436.  
  437.                   functionp = tmpfuncnam;
  438.                   loops     = 0;
  439.                 }
  440.                 else if((fnlen > 1) && ((functionp[fnlen-1] == 'A') && (functionp[fnlen-2] >= 'a') && (functionp[fnlen-2] <= 'z')))
  441.                 {
  442.                   /*  Not that smart recognition... But you probably
  443.                   **  don't want to have a function CreateDA() varargs,
  444.                   **  want you?
  445.                   **
  446.                   **  Recognized are functions that end with 'A' and that
  447.                   **  have a lowercase letter before that.
  448.                   */
  449.  
  450.                   strcpy(tmpfuncnam, functionp);
  451.                   tmpfuncnam[fnlen-1] = '\0';
  452.  
  453.                   functionp = tmpfuncnam;
  454.                   loops     = 0;
  455.                 }
  456.  
  457.                 if(!loops)
  458.                 {
  459.                   if(mode & DEBUG) puts("Found via internal logic!");
  460.                 }
  461.               }
  462.  
  463.               if(loops) for(i=0; p != NULL; i+=2)
  464.               {
  465.                 if(!strcmp(p, functionp))
  466.                 {
  467.                     if(mode & DEBUG) puts("Found!");
  468.  
  469.                     functionp = (char *) varargs[i - 1];        /* [i+1] */
  470.                     loops = 0;
  471.                     break;
  472.                 }
  473.  
  474.                 /*i += 2;*/
  475.                 p = (char *) varargs[i];
  476.               }
  477.             }
  478.         }
  479.  
  480.         offset += 6;
  481.     } /* for(;;) */
  482.  
  483.     if(name) fclose(fd);
  484.  
  485.     fputs("\n\tend\n", lvos);
  486.  
  487.     fclose(lvos);
  488. }
  489.  
  490. /*  Append '/' to path if needed
  491. */
  492.  
  493. static void
  494. fillpath(char *dirpath)
  495. {
  496.   int sl = strlen(dirpath);
  497.  
  498.   switch(dirpath[sl-1])
  499.   {
  500.     case ':':   /* ':' should be AMIGA-only! This will be commented out. */
  501.     case '/':
  502.       break;
  503.  
  504.     default:
  505.       strcpy(dirpath+sl, "/");
  506.       break;
  507.   }
  508. }
  509.  
  510. /*  Show program usage
  511. */
  512.  
  513. static void Usage(const char *) NORETURN;
  514.  
  515. static void
  516. Usage(const char *myname)
  517. {
  518.   printf("fd2libPPC (c) by Volker Barthelmann / Johnny Teveßen\n"
  519.          "\n"
  520.          "  -- Caution: Needs ~5000 byte stack! --\n"
  521.          "\n"
  522.          "Usage : %s [-sd] [-nv] [-o <dir>] [-of <format>]\n"
  523.          "           [-d] [-?|--help] [files/pattern]\n"
  524.          "\n"
  525.          "  -sd : Use small data model (else large data model)\n"
  526.          "  -nv : No varargs logic - ...A and ...TagList will not be detected\n"
  527.          "  -o  : Specify directory to store source files in\n"
  528.          "  -of : C printf style output format to generate compiling\n"
  529.          "        script. Three `%%s' are replaced with output file name\n"
  530.          "  -d  : Turn on debugging/verbose mode\n"
  531.          "  -?  : Show help/version and quit\n"
  532.          "files : FD files to convert, defaults to stdin\n"
  533.          "\n"
  534.          "Commandline is parsed left-to-right. Specifying\n"
  535.          "\"alib_lib.fd -sd blib_lib.fd\" will result in alib\n"
  536.          "getting large data model.\n",
  537.          myname
  538.         );
  539.  
  540.   exit(0);
  541. }
  542.  
  543. /*  Remember: ixemul.library does command line expansion, eg.:
  544. **
  545. **  redrose# fd2lib -sc -sd /fd/a*_lib.fd
  546. **
  547. **  will become:
  548. **
  549. **  redrose# fd2lib -sc -sd /fd/amigaguide_lib.fd /fd/asl_lib.fd ...
  550. **
  551. */
  552.  
  553. int
  554. main(int argc, char **argv)
  555. {
  556.     int erg       = 0 /*EXIT_FAILURE*/;
  557.     int mode      = NEWNOTATE | VARGSLOGIC;
  558.     int filesdone = 0;
  559.  
  560.     char outdir[80] = "", outform[250] = "";
  561.  
  562.     if(argc > 1)
  563.     {
  564.       int i;
  565.  
  566.       for(i=1; i<argc; i++)
  567.       {
  568.         if(argv[i][0] == '-')
  569.         {
  570.           /* Parse option */
  571.  
  572.                if( !strcmp(argv[i], "-sd")) mode |=  SMALLDATA;
  573.           else if( !strcmp(argv[i], "-nv")) mode &= ~VARGSLOGIC;
  574.           else if( !strcmp(argv[i], "-o" ))
  575.           {
  576.             if(i < (argc-1))
  577.             {
  578.               i ++;
  579.  
  580.               if(strlen(argv[i]) < sizeof(outdir))
  581.               {
  582.                 strcpy  (outdir, argv[i]);
  583.                 fillpath(outdir);
  584.               }
  585.               else
  586.               {
  587.                 fprintf(stderr, "Path too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outdir));
  588.               }
  589.             }
  590.             else
  591.             {
  592.               fputs("No path specified after `-o'!\n", stderr);
  593.             }
  594.           }
  595.           else if( !strcmp(argv[i], "-of"))
  596.           {
  597.             if(i < (argc-1))
  598.             {
  599.               i ++;
  600.  
  601.               if(strlen(argv[i]) < sizeof(outform))
  602.               {
  603.                 strcpy(outform, argv[i]);
  604.                 strcat(outform, "\n"   );
  605.               }
  606.               else
  607.               {
  608.                 fprintf(stderr, "Format too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outform));
  609.               }
  610.             }
  611.             else
  612.             {
  613.               fputs("No format specified after `-of'!\n", stderr);
  614.             }
  615.           }
  616.           else if( !strcmp(argv[i], "-d" )) mode |=  DEBUG;
  617.           else if((!strcmp(argv[i], "-?" )) ||
  618.                   (!strcmp(argv[i], "--help"))) Usage(*argv);
  619.           else
  620.           {
  621.             fprintf(stderr, "Unknown option `%s'\n\n", argv[i]);
  622.             Usage(*argv);
  623.           }
  624.         }
  625.         else
  626.         {
  627.           /* Process file */
  628.  
  629.           if(argv[i][0] == '?') Usage(*argv);
  630.           else
  631.           {
  632.             ProcessFD(argv[i], mode, outdir, outform);
  633.             filesdone ++;
  634.           }
  635.         }
  636.       }
  637.     }
  638.  
  639.     if(!filesdone) ProcessFD(NULL, mode, outdir, outform);
  640.  
  641.     return(erg);
  642. }
  643.